package net.cl.util.ui;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;

import net.cl.util.ui.SlideshowPanel.SlideOrientation;


/**
 * Special LayoutManager exclusively designed for the SlideshowPanel class.
 *
 * Lays out the sequence of slides either horizontally or vertically.
 *
 * @author David
 */
class SlideshowRowLayout implements LayoutManager
{
	private int					mMinWidth			= 0;
	private int					mMinHeight			= 0;
	private int					mPreferredWidth		= 0;
	private int					mPreferredHeight	= 0;
	private boolean				mSizeUnknown		= true;

	private SlideOrientation	mOrientation;
	private int					mComponentGap		= 0;

	public SlideshowRowLayout(SlideOrientation pOrientation)
	{
		this.mOrientation = pOrientation;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void addLayoutComponent(String arg0, Component arg1)
	{
		// - Not needed -
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeLayoutComponent(Component arg0)
	{
		// - Not needed -
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Dimension minimumLayoutSize(Container pParent)
	{
		updateSize(pParent);

		Insets insets = pParent.getInsets();
		int width = this.mMinWidth + insets.left + insets.right;
		int height = this.mMinHeight+ insets.top + insets.bottom;

		return new Dimension(width, height);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Dimension preferredLayoutSize(Container pParent)
	{
		updateSize(pParent);

		Insets insets = pParent.getInsets();
		int width = this.mPreferredWidth + insets.left + insets.right;
		int height = this.mPreferredHeight + insets.top + insets.bottom;

		return new Dimension(width, height);
	}

	@Override
	public void layoutContainer(Container pParent)
	{
		if(this.mSizeUnknown)
		{
			this.updateSize(pParent);
		}

		if(this.mOrientation == SlideOrientation.VERTICAL)
		{
			this.doVerticalLayout(pParent);
		}
		else
		{
			this.doHorizontalLayout(pParent);
		}
	}

	private void doHorizontalLayout(Container pParent)
	{
		Insets insets = pParent.getInsets();
		SlideshowContentPane parent = this.ensureContainerType(pParent);

		int position = 0;
		int availableWidth = parent.getMaxWidthPerComponent();
		int availableHeight = parent.getMaxHeightPerComponent();

		// Cycle through all the components and lay them out in a straight line.
		for(Component comp : pParent.getComponents())
		{
			// Every component has the same height, but may have it's own width
			int maxWidth = comp.getMaximumSize() != null ? comp.getMaximumSize().width : Integer.MAX_VALUE;
			int width = Math.min(availableWidth, maxWidth);

			comp.setSize(width, availableHeight);
			comp.setLocation(insets.left + position, insets.top);

			position += width + this.mComponentGap;
		}
	}

	private void doVerticalLayout(Container pParent)
	{
		Insets insets = pParent.getInsets();
		SlideshowContentPane parent = this.ensureContainerType(pParent);

		int position = 0;
		int availableWidth = parent.getMaxWidthPerComponent();
		int availableHeight = parent.getMaxHeightPerComponent();

		// Cycle through all the components and lay them out in a straight line.
		for(Component comp : pParent.getComponents())
		{
			// Every component has the same width, but may have it's own height
			int maxHeight = comp.getMaximumSize() != null ? comp.getMaximumSize().height : Integer.MAX_VALUE;
			int height = Math.min(availableHeight, maxHeight);

			comp.setSize(availableWidth, height);
			comp.setLocation(insets.left, insets.top + position);

			position += height + this.mComponentGap;
		}
	}

	/**
	 * Updates the preferred and minimum size of the layout.
	 *
	 * @param pParent The parent component. Must be of type SlidingPanel.
	 * @throws IllegalArgumentException if pCont is not of type SlidingPanel
	 */
	private void updateSize(Container pParent)
	{
		// Reset preferred/minimum width and height.
		this.mPreferredWidth = 0;
		this.mPreferredHeight = 0;
		this.mMinWidth = 0;
		this.mMinHeight = 0;

		// Compute the sizes as the maximum of all the component's values
		for(Component c : pParent.getComponents())
		{
			this.mPreferredWidth = Math.max(this.mPreferredWidth, c.getPreferredSize().width);
			this.mPreferredHeight = Math.max(this.mPreferredHeight, c.getPreferredSize().height);
			this.mMinWidth = Math.max(this.mMinWidth, c.getMinimumSize().width);
			this.mMinHeight = Math.max(this.mMinHeight, c.getMinimumSize().height);
		}

		this.mSizeUnknown = false;
	}

	@Override
	public String toString()
	{
		return getClass().getSimpleName();
	}

	void setComponentGap(int pGap)
	{
		this.mComponentGap = pGap;
	}

	/**
	 * Checks the type of the argument. If argument is not a SlideshowContentPane, an exception is thrown.
	 *
	 * @param pCont The container to check
	 * @return pCont, but casted to SlideshowContentPane
	 * @throws IllegalArgumentException if pCont is not of type SlideshowContentPane
	 */
	private SlideshowContentPane ensureContainerType(Container pCont)
	{
		if(pCont instanceof SlideshowContentPane)
		{
			return (SlideshowContentPane) pCont;
		}
		else
		{
			throw new IllegalArgumentException("SlidingLayout must operate on a SlideshowContentPane!");
		}
	}
}